﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Web.Mvc;
using SW.Lite.BLL.Master;
using SW.Lite.Infrastructure.Common;
using SW.Lite.Infrastructure.Helpers;
using SW.Lite.Model.Master;

namespace SW.Lite.Core.Authority
{
    /// <summary>
    ///     Class MenuAttribute.
    /// </summary>
    public class MenuAttribute : ActionFilterAttribute
    {
        /// <summary>
        ///     Gets or sets the menu code.
        /// </summary>
        /// <value>The menu code.</value>
        public string MenuCode { get; set; }

        /// <summary>
        ///     Gets the current menu.
        /// </summary>
        /// <value>The current menu.</value>
        public MenuModel CurrentMenu { get; private set; }

        /// <summary>
        ///     Gets or sets the special roles.
        /// </summary>
        /// <value>The special roles.</value>
        public string SpecialRoles { get; set; }

        /// <summary>
        ///     Gets the final roles.
        /// </summary>
        /// <value>The final roles.</value>
        public List<RoleModel> FinalRoles { get; private set; }

        /// <summary>
        ///     Gets or sets a value indicating whether this instance is ajax.
        /// </summary>
        /// <value><c>true</c> if this instance is ajax; otherwise, <c>false</c>.</value>
        public bool IsAjax { get; set; }

        /// <summary>
        ///     Called by the ASP.NET MVC framework before the action method executes.
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var controller = filterContext.Controller as BaseController;
            if (controller == null)
            {
                ReturnResult(filterContext);
                return;
            }

            if (!controller.Validate())
            {
                ReturnResult(filterContext);
                return;
            }

            if (!String.IsNullOrEmpty(SpecialRoles))
            {
                var roles = SpecialRoles.Split(',');
                FinalRoles = controller.Roles.Union(Role.GetRolesByCodes(roles)).ToList();
            }
            else
            {
                FinalRoles = new List<RoleModel>();
                FinalRoles.AddRange(controller.Roles);
            }

            PrepareMenus(filterContext);
            base.OnActionExecuting(filterContext);
        }

        /// <summary>
        ///     Prepares the menus.
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        private void PrepareMenus(ActionExecutingContext filterContext)
        {
            var menus = Menu.GetMenusByRoleIds(FinalRoles.Select(r => r.Id).ToArray());

            var orderMenus = menus.Where(m => m.ParentID == 0).OrderBy(m => m.Sort).Select(m =>
            {
                var children = menus.Where(c => c.ParentID == m.Id).OrderBy(c => c.Sort).Select(c => new MenuModel
                {
                    Id = c.Id,
                    ActionName = c.ActionName,
                    Code = c.Code,
                    ControllerName = c.ControllerName,
                    Icon = c.Icon,
                    ParentID = c.ParentID,
                    Sort = c.Sort,
                    Title = c.Title
                });

                return new MenuModel
                {
                    Id = m.Id,
                    ActionName = m.ActionName,
                    Code = m.Code,
                    ControllerName = m.ControllerName,
                    Icon = m.Icon,
                    ParentID = m.ParentID,
                    Sort = m.Sort,
                    Title = m.Title,
                    Children = new Collection<MenuModel>(children.ToList())
                };
            }).ToList();

            filterContext.Controller.ViewBag.Menus = orderMenus;
            filterContext.Controller.ViewBag.MenuCode = MenuCode;
            var menu = Menu.GetMenuByCode(MenuCode);
            CurrentMenu = menu;
            filterContext.Controller.ViewBag.CurrentMenu = menu;
            filterContext.Controller.ViewBag.Title = menu.Title;
        }

        /// <summary>
        ///     Returns the result.
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public virtual void ReturnResult(ActionExecutingContext filterContext)
        {
            if (!IsAjax)
                filterContext.Result =
                    new RedirectResult("~/Master/Login?ReturnUrl=" +
                                       filterContext.HttpContext.Server.UrlEncode(
                                           filterContext.HttpContext.Request.RawUrl));
            else
                filterContext.Result = new JsonResult { Data = new ExecuteResult { Result = false, Message = "没有权限" } };
        }
    }
}